﻿using Microsoft.Xna.Framework;
using Neat;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Neat.GUI;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Logika;
using Microsoft.Xna.Framework.Input;

namespace RattlerRace
{
    class GameScreen : Screen
    {
        int score = 0;
        int time = 30000;
        int life = 4;
        int level = 1;
        SpriteFont spriteFont;
        SpriteBatch spriteBatch;
        Texture2D myImage;
        NarediSobo narediSobo;
        Snake snake;
        Snake enemySnake;
        DateTime pts, nts;
        TimeSpan passed, tick;
        KeyboardState prevKeyboardState, currentKeyboardState;
        bool controlEnemySnake = false;
        bool play;
        public bool Play
        {
            get { return play; }
            set { play = value; }
        }

        Random r = new Random();
        List<Jabolko> jabolke=new List<Jabolko>(10);
        public string rdecaJabolka = "appleRed";
        public string zlataJabolka = "appleGold";

        public void pojejJabolko()
        {
            for (int i = 0; i < jabolke.Count(); i++)
            {
                if ((snake.snakeBody[snake.snakeBody.Count() - 1].X == jabolke[i].getPozicija().X) && (snake.snakeBody[snake.snakeBody.Count() - 1].Y == jabolke[i].getPozicija().Y))
                {
                    Game1.GameStats.Score += (jabolke[i].getGold() == true) ? 4 : 1;
                    if (Game1.GameStats.Score % 50 == 0) Game1.GameStats.Score++;
                    jabolke.RemoveAt(i);
                    //dodaj točke za jabolko
                    snake.povecajKaco(1);

                    break;
                }
                if ((enemySnake.snakeBody[enemySnake.snakeBody.Count() - 1].X == jabolke[i].getPozicija().X) && (enemySnake.snakeBody[enemySnake.snakeBody.Count() - 1].Y == jabolke[i].getPozicija().Y))
                {
                    jabolke.RemoveAt(i);
                    //pomanjšaj točke za jabolko
                    enemySnake.povecajKaco(1);
                    break;
                }
            }

            if (jabolke.Count == 0)
            {

                novLevel();
            }
        }

        public void novLevel() {
            Game1.GameStats.CurLevel++;
            play = false;
            Initialize();
            base.game.Console.Run("e_show  startlevelscreen");
            //Activate();
        }

        public void postaviJabolke()
        {
            jabolke.Clear();
            Random random = new Random();
            int x, y;
            int zlata = random.Next(0, 10);
            for(int i=0; i<10; i++)
            {
                x = random.Next(1, 32);
                y = random.Next(1, 32);
                jabolke.Add(new Jabolko());
                jabolke[i].izr_poz(x, y);
                if (i == zlata) jabolke[i].setGold(true);
            }
            /*jabolke.Add(new Jabolko());
            jabolke[0].izr_poz(12, 8);
            jabolke.Add(new Jabolko());
            jabolke[1].izr_poz(12, 16);
            jabolke.Add(new Jabolko());
            jabolke[2].izr_poz(20, 20);*/
        }

        public GameScreen(NeatGame Game)
                : base(Game)
            {
            }

            public override void Initialize()
            {
                                base.game.ShowMouse = false;
                base.Initialize();
                spriteBatch = new SpriteBatch(base.game.GraphicsDevice);
                postaviJabolke();

                narediSobo = new NarediSobo();
                narediSobo.beri(base.game.Content.RootDirectory + "/sobe/soba" + Game1.GameStats.CurLevel + ".xml");
                myImage = base.game.Content.Load<Texture2D>("Sprites/GameThumbnail");

                currentKeyboardState = new KeyboardState();
                nts = DateTime.Now;
                passed = new TimeSpan();
                tick = new TimeSpan(0, 0, 0, 0, 200);
                snake = new Snake();
                snake.addPart(16, 24);
                snake.addPart(16, 23);
                snake.addPart(16, 22);
                snake.addPart(16, 21);
                snake.addPart(16, 20);
                enemySnake = new Snake();
                enemySnake.addPart(16, 2);
                enemySnake.addPart(16, 3);
                enemySnake.addPart(16, 4);
                enemySnake.addPart(16, 5);
                enemySnake.addPart(16, 6);
                enemySnake.setDirection(4);
                enemySnake.setDirection(2);
                time = 30000;
                play = false;
            }

            public override void Activate()
            {
                Initialize();
                play = true;
                base.Activate();
            }

            public override void Behave(GameTime gameTime)
            {
                if (!play) return;
                base.Behave(gameTime);
                pts = nts;
                nts = DateTime.Now;
                passed += nts - pts;
                if (passed > tick)
                {
                    passed -= tick;
                    if (snake.getAlive() && !snake.move(narediSobo, enemySnake))
                    {
                        snake.setAlive(false);
                        if (Game1.GameStats.Life == 1) base.game.Console.Run("e_show gameoverscreen");
                        else Game1.GameStats.Life--;

                        Initialize();
                        Activate();

                    }
                    if (enemySnake.getAlive() && !enemySnake.move(narediSobo, snake))
                    {
                        int tries = 20;
                        do
                        {
                            int rand = r.Next(1, 5) * 2;
                            enemySnake.setDirection(rand);
                            tries--;
                        } while (!enemySnake.move(narediSobo, snake) && tries > 0);
                        if (tries == 0)
                        {
                            enemySnake.odstraniRep();
                            if (enemySnake.kacaMrtva())
                            {
                                enemySnake.setAlive(false);
                                ////////////////naprotna kaca mrtva
                            }
                        }
                    }
                }
                time = time - gameTime.ElapsedGameTime.Milliseconds;
                if ((time / 1000 < 0))
                {
                    if (Game1.GameStats.Life == 1) base.game.Console.Run("e_show gameoverscreen");
                    else Game1.GameStats.Life--;

                    Initialize();
                    Activate();
                }
                pojejJabolko();
            }

            public override void HandleInput(GameTime gameTime)
            {
                if (!play) return;
                base.HandleInput(gameTime);
                prevKeyboardState = currentKeyboardState;
                currentKeyboardState = Keyboard.GetState();
                if (currentKeyboardState.IsKeyDown(Keys.Left))
                {
                    snake.setDirection(4);
                }
                else if (currentKeyboardState.IsKeyDown(Keys.Right))
                {
                    snake.setDirection(6);
                }
                else if (currentKeyboardState.IsKeyDown(Keys.Up))
                {
                    snake.setDirection(8);
                }
                else if (currentKeyboardState.IsKeyDown(Keys.Down))
                {
                    snake.setDirection(2);
                }

                if (!prevKeyboardState.IsKeyDown(Keys.E) && currentKeyboardState.IsKeyDown(Keys.E))
                {
                    controlEnemySnake = !controlEnemySnake;
                }

                if (controlEnemySnake)
                {
                    if (currentKeyboardState.IsKeyDown(Keys.A))
                    {
                        enemySnake.setDirection(4);
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.D))
                    {
                        enemySnake.setDirection(6);
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.W))
                    {
                        enemySnake.setDirection(8);
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.S))
                    {
                        enemySnake.setDirection(2);
                    }
                }
                else
                {
                    /*if (r.Next(1, 6) == 5)
                    {
                        int newDir = r.Next(1, 4) * 2;
                        enemySnake.setDirection(newDir);
                    }*/
                    SnakePart glava = enemySnake.getSnakeBody()[enemySnake.getSnakeBody().Count - 1];
                    //Jabolko najblizje = najdiNajblizje(enemySnake.getSnakeBody()[enemySnake.getSnakeBody().Count - 1], jabolke);
                    if (jabolke.Count > 0)
                        enemySnake.setDirection(najdiOptimalnoPot(enemySnake.getSnakeBody()[enemySnake.getSnakeBody().Count - 1]));
                    else
                    {
                        if (r.Next(1, 6) == 5)
                        {
                            int newDir = r.Next(1, 4) * 2;
                            enemySnake.setDirection(newDir);
                        }
                    }
                    /*if (Math.Abs(glava.X - najblizje.getPozicija().X) < Math.Abs(glava.Y - najblizje.getPozicija().Y)) {
                        if (glava.Y - najblizje.getPozicija().Y < 0)
                        {
                            enemySnake.setDirection(2);
                        }
                        else
                        {
                            enemySnake.setDirection(8);
                        }
                    }
                    else
                    {
                        if (glava.X - najblizje.getPozicija().X < 0)
                        {
                            enemySnake.setDirection(6);
                        }
                        else
                        {
                            enemySnake.setDirection(4);
                        }
                    }*/
                }
            }

            public int najdiOptimalnoPot(SnakePart glava)
            {
                List<Point> pot = najdiNaslednjiKvadratek(glava);
                if (pot == null)
                {
                    return r.Next(1, 5) * 2;
                }
                /*foreach (Point pt in pot)
                {
                    Console.WriteLine(pt);
                }
                Console.WriteLine("HERE" + pot[1].X + " " + glava.X);
                Console.Read();*/
                SnakePart glavaVPolju = new SnakePart();

                glavaVPolju.X = glava.X - 1;
                glavaVPolju.Y = glava.Y - 1;
                

                Point nasledni= pot[1];
                if (nasledni.X == glavaVPolju.X + 1) //desno
                {
                    return 6;
                }
                else if (nasledni.X == glavaVPolju.X - 1) //levo
                {
                    return 4;
                }
                else if (nasledni.Y == glavaVPolju.Y + 1) //dol
                {
                    return 2;
                }//gor
                return 8;
            }

            public List<Point> najdiNaslednjiKvadratek(SnakePart p)
            {
                int[,] polje = new int[31, 31];
                for (int i = 0; i < narediSobo.tocke.Count; i++)
                {
                    if (narediSobo.tocke[i][0]/20 != 0 && narediSobo.tocke[i][0]/20 != 32 && narediSobo.tocke[i][1]/20 != 0 && narediSobo.tocke[i][1]/20 != 32)
                        polje[narediSobo.tocke[i][0]/20 - 1, narediSobo.tocke[i][1]/20 - 1] = 1;
                }
                for (int i = 0; i < snake.getSnakeBody().Count; i++)
                {
                    polje[snake.getSnakeBody()[i].X - 1, snake.getSnakeBody()[i].Y - 1] = 1;
                }
                for (int i = 0; i < enemySnake.getSnakeBody().Count; i++)
                {
                    polje[enemySnake.getSnakeBody()[i].X - 1, enemySnake.getSnakeBody()[i].Y - 1] = 1;
                }
                for (int i = 0; i < jabolke.Count; i++)
                {
                    polje[jabolke[i].getPozicija().X - 1, jabolke[i].getPozicija().Y - 1] = 2;
                }
                /*string s = "";
                for (int i = 0; i < 31; i++)
                {
                    for (int j = 0; j < 31; j++)
                    {
                        s += polje[j, i] + "";
                    }
                    s += "\n";
                }
                Console.WriteLine(s);
                Console.Read();*/
                List<List<Point>> seznam = new List<List<Point>>();
                Point zacetna = new Point(p.X-1, p.Y-1);
                polje[p.X-1, p.Y-1] = 1;
                List<Point> zacetni = new List<Point>();
                zacetni.Add(zacetna);
                seznam.Add(zacetni);
                List<Point> trenutni;
                do
                {
                    if (seznam.Count == 0) return null;
                    trenutni = seznam[0].ToList();
                    seznam.RemoveAt(0);
                    Point zadna = trenutni[trenutni.Count - 1];
                    if (zadna.X > 0 && polje[zadna.X - 1, zadna.Y] != 1)
                    {
                        if (polje[zadna.X - 1, zadna.Y] == 2)
                        {
                            //if (trenutni.Count == 1) return new Point(zadna.X - 1, zadna.Y);
                            //return trenutni[1];
                            List<Point> temp2 = trenutni.ToList();
                            temp2.Add(new Point(zadna.X-1, zadna.Y));
                            return temp2;
                        }
                        List<Point> temp = trenutni.ToList();
                        temp.Add(new Point(zadna.X - 1, zadna.Y));
                        polje[zadna.X - 1, zadna.Y] = 1;
                        seznam.Add(temp);
                    }
                    if (zadna.X < 30 && polje[zadna.X + 1, zadna.Y] != 1)
                    {
                        if (polje[zadna.X + 1, zadna.Y] == 2)
                        {
                            //if (trenutni.Count == 1) return new Point(zadna.X + 1, zadna.Y);
                            //return trenutni[1];
                            List<Point> temp2 = trenutni.ToList();
                            temp2.Add(new Point(zadna.X+1, zadna.Y));
                            return temp2;
                        }
                        List<Point> temp = trenutni.ToList();
                        temp.Add(new Point(zadna.X + 1, zadna.Y));
                        polje[zadna.X + 1, zadna.Y] = 1;
                        seznam.Add(temp);
                    }
                    if (zadna.Y > 0 && polje[zadna.X, zadna.Y - 1] != 1)
                    {
                        if (polje[zadna.X, zadna.Y - 1] == 2)
                        {
                            //if (trenutni.Count == 1) return new Point(zadna.X, zadna.Y - 1);
                            //return trenutni[1];
                            List<Point> temp2 = trenutni.ToList();
                            temp2.Add(new Point(zadna.X, zadna.Y - 1));
                            return temp2;
                        }
                        List<Point> temp = trenutni.ToList();
                        temp.Add(new Point(zadna.X, zadna.Y - 1));
                        polje[zadna.X, zadna.Y - 1] = 1;
                        seznam.Add(temp);
                    }
                    if (zadna.Y < 30 && polje[zadna.X, zadna.Y + 1] != 1)
                    {
                        if (polje[zadna.X, zadna.Y + 1] == 2)
                        {
                            //if (trenutni.Count == 1) return new Point(zadna.X, zadna.Y + 1);
                            //return trenutni[1];
                            List<Point> temp2 = trenutni.ToList();
                            temp2.Add(new Point(zadna.X, zadna.Y + 1));
                            return temp2;
                        }
                        List<Point> temp = trenutni.ToList();
                        temp.Add(new Point(zadna.X, zadna.Y + 1));
                        polje[zadna.X, zadna.Y + 1] = 1;
                        seznam.Add(temp);
                    }
                    /*Console.WriteLine("zadna:" + zadna.X + " " + zadna.Y);
                    foreach (List<Point> l in seznam)
                    {
                        foreach (Point pt in l)
                        {
                            Console.Write(pt.ToString() + " | ");
                        }
                        Console.WriteLine();
                    }*/
                    //Console.WriteLine(seznam.Count.ToString()); Console.Read();
                    /*string s = "";
                    for (int i = 0; i < 31; i++)
                    {
                        for (int j = 0; j < 31; j++)
                        {
                            s += polje[j, i] + "";
                        }
                        s += "\n";
                    }
                    Console.WriteLine(s);
                    Console.WriteLine();*/
                } while (true);
            }

            /*public Jabolko najdiNajblizje(SnakePart p, List<Jabolko> jabolke)
            {
                int r = razdalja(p, jabolke[0]);
                Jabolko najblizje = jabolke[0];
                for (int i = 1; i < jabolke.Count; i++)
                {
                    int nova = razdalja(p, jabolke[i]);
                    if (nova < r) {
                        r = nova;
                        najblizje = jabolke[i];
                    }
                }
                return najblizje;
            }

            public int razdalja(SnakePart p, Jabolko j)
            {
                return Math.Abs(p.X - j.getPozicija().X) + Math.Abs(p.Y - j.getPozicija().Y);
            }*/

            public override void Render(GameTime gameTime)
            {
                if (!play) return;
                List<SnakePart> snakeParts = snake.getSnakeBody();
                List<SnakePart> enemySnakeParts = enemySnake.getSnakeBody();
                
                spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
                
                for (int i = 0; i < narediSobo.tocke.Count; i++)
                {

                    SpriteBatch.Draw(game.GetTexture("gameThumbnail"), new Vector2(narediSobo.tocke[i][0], narediSobo.tocke[i][1]), Color.White);

                }
                //spriteBatch.Draw(myImage, Position, Color.White);
                for (int i = 0; i < snakeParts.Count; i++)
                {
                    spriteBatch.Draw(game.GetTexture("snake"), new Vector2(snakeParts[i].X * 20, snakeParts[i].Y * 20), Color.White);
                }
                for (int i = 0; i < enemySnakeParts.Count; i++)
                {
                    spriteBatch.Draw(game.GetTexture("enemysnake"), new Vector2(enemySnakeParts[i].X * 20, enemySnakeParts[i].Y * 20), Color.White);
                }
                for (int i = 0; i < jabolke.Count(); i++)
                {
                    if (jabolke[i].getGold() == false)
                    {
                        spriteBatch.Draw(game.GetTexture("appleRed"), new Vector2(jabolke[i].getPozicija().X * 20, jabolke[i].getPozicija().Y * 20), Color.White);
                    }
                    else
                    {
                        spriteBatch.Draw(game.GetTexture("appleGold"), new Vector2(jabolke[i].getPozicija().X * 20, jabolke[i].getPozicija().Y * 20), Color.White);
                    }
                }

                spriteBatch.DrawString(game.GetFont("Arial"), "Score: " + Game1.GameStats.Score, new Vector2(37, 40), Color.White);
                spriteBatch.DrawString(game.GetFont("Arial"), "Life: " + Game1.GameStats.Life, new Vector2(37, 55), Color.White);
                spriteBatch.DrawString(game.GetFont("Arial"), "Remaining time: " + time / 1000, new Vector2(37, 25), Color.White);
                spriteBatch.End();
                base.Render(gameTime);

            }
    }
}
